﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Windows.Forms;
using System.Threading.Tasks;
using System.IO;
using System.Drawing;
using System.Net.Sockets;

namespace TcpClientDemo
{
	/// <summary>
	/// TCP客户端例子
	/// </summary>
    public partial class TcpClientDemo : Form
    {
        #region 字段

        /// <summary>
        /// 存储网卡的IP信息
        /// </summary>
        private Dictionary<string, string> dit;

        /// <summary>
        /// 申明TcpClient
        /// </summary>
        private TcpClient _tcpClient = null;

        /// <summary>
        /// 收发数据的长度计数
        /// </summary>
        private int recvlen = 0;
		private int sendlen = 0;

        /// <summary>
        /// 服务端的IP 和 端口
        /// </summary>
		private string serverIpstr = "";
		private int serverPort = -1;

        /// <summary>
        /// 是否建立链接
        /// </summary>
        private bool isConnected = false;

        /// <summary>
        /// 接收数据缓冲区大小64K
        /// </summary>
        private const int DefaultBufferSize = 64 * 1024;

        /// <summary>
        /// 接收数据缓冲区
        /// </summary>
        private readonly byte[] _recvDataBuffer = new byte[DefaultBufferSize];

        /// <summary>
        /// 网络数据流，Nmodbus4使用的是这种方式来处理数据的，
        /// 所以Nmodbus4是同步阻塞的
        /// </summary>
        //private NetworkStream m_networkStream;

        /// <summary>
        /// 客户端退出类型
        /// </summary>
        private enum ExitType
        {
            /// <summary>
            /// 用户退出
            /// </summary>
            ClientExit,
            /// <summary>
            /// 正常退出
            /// </summary>
            NormalExit,
            /// <summary>
            /// 异常关闭
            /// </summary>
            ExceptionExit
        };
        #endregion


        #region 构造函数
        /// <summary>
        /// TcpClientDemo
        /// </summary>
        public TcpClientDemo()
        {
            //初始化组建
            InitializeComponent();
			
			//获取网卡信息
			dit =NetworkCardHelper.GetAllNetWorkCardDictionary();
            if (dit != null)
            {
                foreach (var item in dit.Values)
                {
                    //将IP赋值到下拉框
                    IPcmb.Items.Add(item);
                }
                //默认索引0
                IPcmb.SelectedIndex = 0;
            }

		}
        #endregion

        #region 客户端方法
        /// <summary>
        /// 断开事件处理
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void ClientDisConnected(ExitType TypeOfExit)
        {
            isConnected = false;
            // 判断退出是用户主动退出
            if (TypeOfExit == ExitType.ClientExit)
            {
                Messagetssl.Text = "连接已断开！！";
            }
            // 判断退出是异常退出
            else if (TypeOfExit == ExitType.ExceptionExit)
            {
                Messagetssl.Text = "服务器异常关闭！！";
                _tcpClient.Close();
            }
            // 其他作为异常服务器退出
            else
            {
                Messagetssl.Text = "服务器已经关闭！！";
                _tcpClient.Close();

            }
            //调用基于——>Action的委托——>委托采用的是匿名函数实现
            this.Invoke(new Action(() => { this.Openbtn.Text = "连接"; }));
        }
       
        /// <summary>
        /// 连接事件处理
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void ClientConnected(Socket e)
        {
            // 更新链接状态
            isConnected = true;

            // 格式化输出的信息字符串
            string info = string.Format("成功连接远程服务器：{0}",
                e.RemoteEndPoint.ToString());

            // 异步跨线程操作控件
            this.Invoke(new Action(() =>
            {
                Messagetssl.Text = info;
                this.Openbtn.Text = "断开";
            }));
        }

        /// <summary>
        /// 数据接收处理
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void ReceivedDataHandler(byte[] recbuffer, int len)
        {
            //调用委托去处理数据
            this.Invoke(new Action<byte[], int>((buffer, lenth) =>
            {
                //未使能命令接收功能
                if (checkBox1.Checked == false)
                {
                    Recivertb.AppendText(Encoding.Default.GetString(buffer, 0, lenth));
                    recvlen += lenth;
                    Recivelab.Text = "" + recvlen;

                }
                else
                {
                    byte[] data = new byte[lenth];                                                      //定义缓冲区
                    recvlen += lenth;
                    Recivelab.Text = "" + recvlen;                                                      //接收数据计数
                    Array.Copy(buffer, data, data.Length);

                    foreach (byte Member in data)                                                       //遍历用法获取已接收的数据，比较慢
                    {
                        string str = Convert.ToString(Member, 16).ToUpper();
                        Recivertb.AppendText((str.Length == 1 ? "0" + str : str) + " ");
                    }
                }
            }
            ), new object[] { recbuffer, len });
        }
        
        #endregion
        
        #region 界面操作
        /// <summary>
        /// 连接断开按钮事件
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void Openbtn_Click(object sender, EventArgs e)
		{
			if (IPcmb.Text == "" || Porttxt.Text == "") {
				MessageBox.Show("IP和端口不能为空");
				return;
			}
			serverIpstr = IPcmb.Text;
			serverPort = Convert.ToInt32(Porttxt.Text);
            try
            {
                // 当前是未连接状态
                if (isConnected == false)
                {
                    // 实例化客户端
                    _tcpClient = new TcpClient();
                    //启动连接后会阻塞线程，所以采用Task避免UI假死
                    //同步
                    //Task.Run(() => {
                    //_tcpClient.Connect(serverIpstr, serverPort);
                    //});		
                    // 异步，启动链接
                    _tcpClient.BeginConnect(serverIpstr, serverPort, new AsyncCallback(Connected), _tcpClient.Client);

                }
                // 已连接状态
                else if (isConnected == true && _tcpClient.Connected)
                {
                    // 断开链接
                    _tcpClient.Close();
                    // 更新断开的UI
                    ClientDisConnected(ExitType.ClientExit);
                }
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message);
            }
			
		}

        /// <summary>
        /// 链接过程的异步回调
        /// </summary>
        /// <param name="ar"></param>
        private void Connected(IAsyncResult ar)
        {
            // 获取参数
            Socket msocket = (Socket)ar.AsyncState;
            try
            {
                // 结束链接请求，必须调用EndConnect。重点。
                msocket.EndConnect(ar);
                // 使用网络数据流来收发数据
                // m_networkStream = _tcpClient.GetStream();
            }
            catch (SocketException ex)
            {
                isConnected = false;
                if (ex.ErrorCode == 10061)
                   Messagetssl.Text = "远程服务器拒绝接入";
                return;
            }
            finally
            {
                // nothing to do...
            }
            // 链接完成更新界面
            ClientConnected(msocket);
            // 启动数据读取，重点 socket下的BeginReceive，异步
            _tcpClient.Client.BeginReceive(_recvDataBuffer, 0,DefaultBufferSize, SocketFlags.None,
              new AsyncCallback(RecivedData), msocket);

        }

        /// <summary>
        /// 接收数据的异步回调
        /// </summary>
        /// <param name="ar"></param>
        private void RecivedData(IAsyncResult ar)
        {
            // 断开状态就返回
            if (isConnected == false) return;
            // 获取Socket对象
            Socket remote = (Socket)ar.AsyncState;
            try
            {
                // 获取接收数据的长度，EndReceive
                int recv = remote.EndReceive(ar);
                //服务端关闭，正常退出
                if (recv == 0)
                {
                    // UI更新
                    ClientDisConnected(ExitType.NormalExit);
                    return;
                }
                //接收数据更新到UI
                ReceivedDataHandler(_recvDataBuffer, recv);
                //继续接收，继续启动接收
                _tcpClient.Client.BeginReceive(_recvDataBuffer, 0, DefaultBufferSize, SocketFlags.None,
                    new AsyncCallback(RecivedData), _tcpClient.Client);
            }
            catch (SocketException ex)
            {
                if (10054 == ex.ErrorCode)
                {
                    //服务器强制的关闭连接，强制退出
                    Messagetssl.Text = $"远程服务器关闭：{ex.ErrorCode}";
                }
                else
                {
                    Messagetssl.Text = $"{ex.Message}";
                }
            }
            catch (ObjectDisposedException ex)
            {
                // 不处理异常
                if (ex != null)
                {
                    ex = null;
                }
            }
        }

        /// <summary>
        /// 发送按钮事件
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void Sendbtn_Click(object sender, EventArgs e)
		{
            if (checkBox1.Checked == false)
            {
                if (Sendrtb != null)
                {
                    Encoding gb = Encoding.GetEncoding("gb2312");
                    sendlen += gb.GetBytes(Sendrtb.Text).Length;
                    Sendlab.Text = "" + sendlen;
                    _tcpClient.Client.Send(Encoding.Default.GetBytes( Sendrtb.Text));
                }
            }
            else
            {
                string hexstr = Sendrtb.Text.Replace(" ", "");
                byte[] te = new byte[DataEncoding.HexStringToBytes(hexstr).Length];
                te = DataEncoding.HexStringToBytes(hexstr);
                Sendlab.Text = "" + te.Length;
                _tcpClient.Client.Send(te);
            }
		}
		
        /// <summary>
		/// 窗体关闭事件处理
		/// </summary>
		/// <param name="sender"></param>
		/// <param name="e"></param>
		private void TcpClientDemo_FormClosing(object sender, FormClosingEventArgs e)
		{
			if (_tcpClient != null) _tcpClient.Close();
		}
		
        /// <summary>
		/// 接收清零
		/// </summary>
		/// <param name="sender"></param>
		/// <param name="e"></param>
		private void Recivelab_Click(object sender, EventArgs e)
		{
			recvlen = 0;
			Recivelab.Text = "0";
		}
		
        /// <summary>
		/// 发送清零
		/// </summary>
		/// <param name="sender"></param>
		/// <param name="e"></param>
		private void Sendlab_Click(object sender, EventArgs e)
		{
			sendlen = 0;
			Sendlab.Text = "0";
		}

        /// <summary>
        /// 接收框清零
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>

        private void Recivertb_DoubleClick(object sender, EventArgs e)
		{
			Recivertb.Text = "";
		}
       
        /// <summary>
        /// 
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void checkBox1_CheckedChanged(object sender, EventArgs e)
        {
            if (Sendrtb.Text == "") return;
            if (checkBox1.CheckState == CheckState.Checked)
            {
                Sendrtb.Text = DataEncoding.ConvertStringToHexString(Sendrtb.Text);
            }
            else
            {
                Sendrtb.Text = DataEncoding.ConvertHexStringToString(Sendrtb.Text);
            }
        }
        
        #endregion
    }
}
